﻿using AutoMapper;
using Newtonsoft.Json;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Zocono.Infrastructure.Common;
using Zocono.WCS.Domain.DomainRepository;
using Zocono.WCS.Domain.EntityInfo;
using Zocono.WCS.Domain.LogDomain;
using Zocono.WCS.Domain.PlcBytesObject;
using Zocono.WCS.Domain.PlcConnectionDomain;
using Zocono.WCS.Domain.PlcConnectPoolDomain;
using Zocono.WCS.Domain.ProcessModuleDomain;
using Zocono.WCS.Infrastructure.ApllicationDto.Enums;
using Zocono.WCS.Infrastructure.ApllicationDto.WCSTaskDto;
using Zocono.WCS.Infrastructure.PlcCommon;
using Zocono.WCS.WMSApiDomain.WebApi;

namespace Zocono.WCS.Domain.EquipmentProcessDomain.PlanarGeneralMessage
{
    /// <summary>
    /// 巷道请求服务//目标位请求
    /// </summary>
    public class AisleRequest1Service : IPlanarGeneralPlcActionProcessService
    {
        private readonly IRedisHelper _IRedisHelper;
        private readonly ISnowflake _snowflake;
        private readonly ILogUtil _logUtil;
        private readonly IMapper _mapper;
        private readonly IPlcConnectionPool _plcConnectionPool;
        private readonly IWorkTaskInfoRepository _workTaskInfoRepository;
        private readonly IPlcWriteDbInfoRepository _plcWriteDbInfoRepository;
        private readonly IPlcConnectionInfoRepository _PlcConnectionInfoRepository;
        private readonly IPlcPointInfoRepositpry _IPlcPointInfoRepositpry;
        private readonly IPlcConnectionStateInfoRepository _IPlcConnectionStateInfoRepository;
        private readonly IRunLogInfoService _IRunLogInfoService;
        private readonly IPlcReadDbInfoRepository _PlcReadeDbInfoRepository;

        public AisleRequest1Service(IRedisHelper iRedisHelper, ISnowflake snowflake, ILogUtil logUtil, IMapper mapper,
            IPlcConnectionPool plcConnectionPool, IWorkTaskInfoRepository workTaskInfoRepository
            , IPlcWriteDbInfoRepository plcWriteDbInfoRepository
            , IPlcPointInfoRepositpry plcPointInfoRepositpry
             , IPlcConnectionInfoRepository plcConnectionInfoRepository
           , IPlcConnectionStateInfoRepository plcConnectionStateInfoRepository
            , IRunLogInfoService runLogInfoService, IPlcReadDbInfoRepository plcReadDbInfoRepository)
        {
            _IRedisHelper = iRedisHelper;
            _snowflake = snowflake;
            _logUtil = logUtil;
            _mapper = mapper;
            _plcConnectionPool = plcConnectionPool;
            _workTaskInfoRepository = workTaskInfoRepository;
            _plcWriteDbInfoRepository = plcWriteDbInfoRepository;
            _PlcConnectionInfoRepository = plcConnectionInfoRepository;
            _IPlcPointInfoRepositpry = plcPointInfoRepositpry;
            _IPlcConnectionStateInfoRepository = plcConnectionStateInfoRepository;
            _IRunLogInfoService = runLogInfoService;
            _PlcReadeDbInfoRepository = plcReadDbInfoRepository;
        }

        public async Task ProcessActionMessageAsync(BytesObjectBase plcActionMessage, BytesObjectBase wcsActionMessage, EquipmentDbObject planarEquipmentDbObject/*, BytesObjectBase plcStateMassge*/)
        {
            /*
             *  需求说明
                1.判断plc状态与设备状态（仅报警处理）
                2.根据任务状态【待执行、执行中】查询wcs托盘上架任务是否存在?（存在则直接回复正常报文 否则请求wms下发入库上架任务）
                  NA说明：1) 根据wms下发任务生成wcs任务
                          2）计算wcs任务路径id【RouteInfo】第一条路径明细【RouteDetailInfo】作为wcs子任务【WorkTaskInfo】Cuttent部分
                          3）更新wms任务状态为执行中
                3.逻辑处理完成 则开始写入Plc 写入成功则处理WCS操作数据库业务 否则不操作
                  说明：1）默认wcs ActionType 跟随Plc ActionType值 即Plc ActionType为 1 则wcs ActionType回写也为 1 
                        2）针对Plc离线或设备状态报警程序直接return
                         plc动作报文托盘号为空或wms请求巷道任务失败 则响应握手类型 =100表示报警
             */


            var plcMessage = plcActionMessage as PlanarGeneralPlcActionBO;//Plc的动作报文
            var wcsMessage = wcsActionMessage as PlanarGeneralWcsActionBO;//Wcs的动作报文
            plcMessage.PalletBarcode = plcMessage.PalletBarcode.Trim();

            RunLogInfo runLogInfo = new();
            runLogInfo.ContainerBarcode = plcMessage.PalletBarcode;
            runLogInfo.EquipmentCode = plcMessage.EquipmentCode;
            runLogInfo.RunType = "巷道/目标位请求1";

            //var plcStateBo = plcStateMassge as PlcOnLineStateBO;//Plc在线离线报文 没有设备信息
            PlanarGeneralWriteWcsAction writeBo = null;//写入Plc的报文
            PlcConnectionS7 plcConn = _plcConnectionPool.S7GetWritePlcConnection(plcMessage.PlcConnectionID);//plc写入连接（不锁定）
            
            if (plcConn == null)
            {
                //runLogInfo.RunLog = $"获取连接({writeBo.PlcConnectionID})失败";
                //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                _logUtil.Error($"请求目标位：托盘【{plcMessage.PalletBarcode}】请求目标位，PLC设备【{plcMessage.PlcConnectionID}】不存在连接池中！");
                return;
            }

            #region Plc离线判断&设备报警判断
            runLogInfo.RunLog = "任务开始：巷道/目标位请求任务开始";
            //1. 验证plc是否在线
            var plcIPStates = await _IPlcConnectionStateInfoRepository.GetFirstAsync(l => l.PlcConnectionID == plcMessage.PlcConnectionID && l.Connected == true);
            if (plcIPStates == null)
            {
                //runLogInfo.RunLog = $"离线：请求分配失败：{plcConn.IP}:plc已离线";
                //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                _logUtil.Error($"请求目标位1：托盘【{plcMessage.PalletBarcode}】请求目标位，PLC设备【{plcMessage.EquipmentCode}】离线！");
                return;
            }



            //设备报警状态判断FBPR005957

            //var stateMessage = planarEquipmentDbObject.bytesObjectBases.Find(o => o.ObjectType.Contains("StateBO"));
            //var planarStateBo = stateMessage as PlanarStateBO;
            //if(planarStateBo == null)
            //{
            //    _logUtil.Info($"请求巷道分配失败：设备编号{plcMessage.EquipmentCode} 状态信息不存在");
            //    return;
            //}

            #endregion

            #region plc写入连接获取&写入报文构建
            //Plc连接Id
            long plcId = wcsMessage.PlcConnectionID;
            //写入plc的报文配置获取
            var objectType = typeof(PlanarGeneralWriteWcsAction).Name;
            var writeConfig = await _plcWriteDbInfoRepository.GetFirstAsync(s => s.EquipmentCode == plcMessage.EquipmentCode && s.ObjectType == objectType);
            if (writeConfig == null)
            {

                //runLogInfo.RunLog = "获取PLC写入配置失败";
                //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                _logUtil.Error($"请求目标位1：托盘【{plcMessage.PalletBarcode}】请求目标位，PLC设备【{plcMessage.EquipmentCode}】写DB配置获取失败！请检查配置！");
                return;
            }

            //构建写入报文
            writeBo = new PlanarGeneralWriteWcsAction(
                writeConfig.PlcConnectionId,
                writeConfig.ID,
                writeConfig.DbCode,
                writeConfig.DbStart,
                objectType,
                plcMessage.EquipmentCode.ToInt32(),
                //Convert.ToInt32(writeConfig.EquipmentCode),
                plcMessage.ActionType,
                plcMessage.ToEquipmentCode,
                taskCode: plcMessage.TaskCode,
                palletBarcode: plcMessage.PalletBarcode,
                plcMessage.PalletType,
                0);
            //托盘号不存在 写入握手类型100报警
            //托盘号不存在 
            if (string.IsNullOrEmpty(plcMessage.PalletBarcode) || plcMessage.PalletBarcode.Length != 10)
            {
                writeBo.ActionType = 99;
                writeBo.AlrmCode = 102;
                var res = await plcConn.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize());
                _logUtil.Error($"请求目标位：请求目标位，PLC设备【{plcMessage.EquipmentCode}】读取托盘信息为空！请检查PLC信息是否写入信息");
                _IRedisHelper.SetStringKey($"PLC-{plcMessage.EquipmentCode}", plcMessage.EquipmentCode.ToString() + plcMessage.AlrmCode, TimeSpan.FromSeconds(10));
                return;
            }
            
            //线体报警
            if (plcMessage.AlrmCode > 0)
            {
                writeBo.ActionType = 99;
                writeBo.AlrmCode = 101;
                var res = await plcConn.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize());
                _logUtil.Error($"请求目标位：请求目标位，PLC设备【{plcMessage.EquipmentCode}】PLC报警！");
                _IRedisHelper.SetStringKey($"PLC-{plcMessage.EquipmentCode}", plcMessage.EquipmentCode.ToString() + plcMessage.AlrmCode, TimeSpan.FromSeconds(10));
                return;
            }

            
            //托盘类型
            switch (writeBo.PalletBarcode.Substring(1, 1))
            {
                case "A":
                    writeBo.PalletType = 2;
                    break;
                case "B":
                    writeBo.PalletType = 1;
                    break;
                case "C":
                    writeBo.PalletType = 3;
                    break;
            }
            #endregion



            //投料口分辨托盘类型
            if (plcMessage.ActionType == 34)
            {
                var writeBl = await plcConn.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize());

                if (writeBl == false)
                {
                    //runLogInfo.RunLog = $"投料口分辨托盘类型：写入报文失败";
                    //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                    _logUtil.Error($"请求目标位：托盘【{plcMessage.PalletBarcode}】投料口分辨托盘类型，PLC设备【{plcMessage.EquipmentCode}】写入PLC失败！");
                }
                else
                {
                    runLogInfo.RunLog = $"请求目标位：托盘【{plcMessage.PalletBarcode}】投料口分辨托盘类型，PLC设备【{plcMessage.EquipmentCode}】写入PLC成功！写入报文内容：{JsonConvert.SerializeObject(writeBo)}";
                    await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                }
                return;
            }



            #region 托盘号不存在&wcs托盘上架任务已存在逻辑处理

            //校验条码
            if (plcMessage.ActionType == 35)
            {
                //获取电芯条码得DB块信息，进行读取
                var plcConfigput = await _PlcReadeDbInfoRepository.GetFirstAsync(l => l.EquipmentCode == plcMessage.EquipmentCode && l.DbLength == 58);


                byte[] bytes = await plcConn.ReadDbAsync(plcConfigput.DbCode, plcConfigput.DbStart, plcConfigput.DbLength);
                if (bytes == null)
                {
                    //runLogInfo.RunLog = $"读DB失败";
                    //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                    _logUtil.Error($"请求目标位：请求目标位，PLC设备【{plcMessage.EquipmentCode}】读取DB获取电芯条码失败！");
                    return;
                }

                PlanarPutBatteryPlcActionBO plcActionBO = new();
                plcActionBO.Serialize(plcConfigput.PlcConnectionID, plcConfigput.ID, plcConfigput.DbStart, plcConfigput.DbLength, plcConfigput.DbStart, plcConfigput.DbLength, "PlanarPutBatteryPlcActionBO", plcConfigput.EquipmentCode, bytes);//主要是bytes转化成明文
                plcActionBO.PalletBarcode = plcActionBO.PalletBarcode.Trim();
                plcActionBO.BatteryCode = plcActionBO.BatteryCode.Trim();
                WCSCombinePalletInfoDto wCSCombinePalletInfoDto = new()
                {
                    ContainerBarcode = plcMessage.PalletBarcode,
                    EquipmentCode = plcMessage.EquipmentCode
                };

                List<WCSOneBatteryDto> list = new()
                {
                    new WCSOneBatteryDto()
                    {
                        BatteryIndex = plcActionBO.BatteryIndex,
                        BatteryCode = plcActionBO.BatteryCode
                    }
                };
                if (plcActionBO.BatteryCode.Length == 0 || plcActionBO.BatteryIndex == 0)
                {
                    //runLogInfo.RunLog = $"电池条码为空或位置信息为0";
                    //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                    writeBo.ActionType = 36;
                    var res = await plcConn.WriteDbAsync(writeConfig.DbCode, writeConfig.DbStart, writeBo.Deserialize());
                    if (res)
                    {
                        runLogInfo.RunLog = $"请求目标位：托盘【{plcMessage.PalletBarcode}】投料口校验电芯失败，PLC设备【{plcMessage.EquipmentCode}】写入PLC成功！写入报文：{JsonConvert.SerializeObject(writeBo)}";
                        //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                        _logUtil.Error(runLogInfo.RunLog);
                    }
                    else
                    {
                        //runLogInfo.RunLog = $"电池条码为空或位置信息为写入报文失败";
                        //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                        _logUtil.Error($"请求目标位：托盘【{plcMessage.PalletBarcode}】投料口校验电芯失败，PLC设备【{plcMessage.EquipmentCode}】写入PLC失败！");
                    }
                    return;
                }

                wCSCombinePalletInfoDto.oneBatteryInfoDtos = list;

                //3 4楼实盘投入口不申请任务直接返回
                string[] inEqs = { "320601", "320603", "320605", "420521", "420523", "420525", "330473", "410503", "410506" };
                //组盘提交数据到WMS
                try
                {
                    var bo = await WCSMessageWithWMSApi.WCSAddComPalletAsync(wCSCombinePalletInfoDto);
                    if (bo)
                    {
                        //runLogInfo.RunLog = $"投料校验成功";
                        //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                        if (inEqs.Contains(plcMessage.EquipmentCode.Trim()))
                        {
                            var res = await plcConn.WriteDbAsync(writeConfig.DbCode, writeConfig.DbStart, writeBo.Deserialize());
                            if (res)
                            {
                                runLogInfo.RunLog = $"请求目标位1：托盘【{plcMessage.PalletBarcode}】投料口校验电芯成功，PLC设备【{plcMessage.EquipmentCode}】写入PLC成功！写入报文：{JsonConvert.SerializeObject(writeBo)}";
                                await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                            }
                            else
                            {
                                //runLogInfo.RunLog = $"托盘校验写入报文失败:托盘校验成功，未申请任务。";
                                //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                                _logUtil.Error($"请求目标位1：托盘【{plcMessage.PalletBarcode}】投料口校验电芯成功，PLC设备【{plcMessage.EquipmentCode}】写入PLC失败！");
                            }
                            return;
                        }
                    }
                    else
                    {
                        writeBo.ActionType = 36;
                        writeBo.AlrmCode = 2;
                        var res = await plcConn.WriteDbAsync(writeConfig.DbCode, writeConfig.DbStart, writeBo.Deserialize());
                        if (res)
                        {
                            runLogInfo.RunLog = $"请求目标位1：托盘【{plcMessage.PalletBarcode}】投料口校验电芯失败，PLC设备【{plcMessage.EquipmentCode}】写入PLC成功！写入报文：{JsonConvert.SerializeObject(writeBo)}";
                            //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                            _logUtil.Error(runLogInfo.RunLog);
                        }
                        else
                        {
                            //runLogInfo.RunLog = $"投料校验写入报文失败:投料校验失败";
                            //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                            _logUtil.Error($"请求目标位1：托盘【{plcMessage.PalletBarcode}】投料口校验电芯失败，PLC设备【{plcMessage.EquipmentCode}】写入PLC失败！");
                        }
                        return;
                    }
                }
                catch(Exception ex)
                {
                    writeBo.ActionType = 36;
                    var res = await plcConn.WriteDbAsync(writeConfig.DbCode, writeConfig.DbStart, writeBo.Deserialize());
                    if (res)
                    {
                        runLogInfo.RunLog = $"请求目标位：托盘【{plcMessage.PalletBarcode}】投料口校验电芯报错：{ex.Message}，PLC设备【{plcMessage.EquipmentCode}】写入PLC成功！写入报文：{JsonConvert.SerializeObject(writeBo)}";
                        //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                        _logUtil.Error(runLogInfo.RunLog);
                    }
                    else
                    {
                        //runLogInfo.RunLog = $"投料校验写入报文失败:投料校验WMS请求失败";
                        //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                        _logUtil.Error($"请求目标位：托盘【{plcMessage.PalletBarcode}】投料口校验电芯报错：{ex.Message}，PLC设备【{plcMessage.EquipmentCode}】写入PLC失败！");
                    }
                    return;
                }

            }


            //前面都通过，则任务开始请求分配重复
            //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
            //判断设备在wcs是否已存在分配巷道任务
            var exp = Expressionable.Create<WorkTaskInfo>();
            exp.AndIF(true, (a) => a.PalletCode == plcMessage.PalletBarcode && (a.TaskState == EnumTaskState.Initial || a.TaskState == EnumTaskState.Executing));
            var wcsWorkTaskInfo = await _workTaskInfoRepository.GetFirstAsync(exp.ToExpression());

            //根据托盘是否存在其它的任务 && 起点位置是否相同判断，存在则写入正常报文Return
            if (wcsWorkTaskInfo != null)
            {
                //runLogInfo.RunLog = $"请求分配重复:任务号：{wcsWorkTaskInfo.TaskCode}入库任务已存在";
                //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                
                _logUtil.Error($"请求目标位：托盘【{plcMessage.PalletBarcode}】任务号：{wcsWorkTaskInfo.TaskCode}任务已存在");
                //如果存在任务则向WMS请求任务返回判断是否和WCS任务一致  一致直接回复握手  如果不一致 则报错 先处理任务
                //向wms读取巷道分配任务
                WMSApiDomain.WebApi.HeaderResult<WmsTaskInfoDto> res = await WCSMessageWithWMSApi.WCSCreatUploadWarehouseWMSTaskAsync(plcMessage.PalletBarcode, plcMessage.EquipmentCode);
                if (res.IsSucceed && res.Result != null)
                {
                    WmsTaskInfoDto workTaskDtoTemp = res.Result;
                    if (workTaskDtoTemp.TaskCode == wcsWorkTaskInfo.WmsTaskCode && wcsWorkTaskInfo.CurrentFromEquipment == plcMessage.EquipmentCode)
                    {
                        //写入正常报文到Plc
                        writeBo.TaskCode = wcsWorkTaskInfo.TaskCode;//wcs任务号
                        writeBo.ToEquipmentCode = wcsWorkTaskInfo.CurrentToEquipment.ToInt32();//目标设备编号

                        //runLogInfo.RunLog = $"PLC写入报文内容： {JsonConvert.SerializeObject(writeBo)}";
                        //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                        //plc给什么握手回什么握手
                        writeBo.ActionType = plcMessage.ActionType;
                        var writeResultTemp = await plcConn.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize());

                        if (writeResultTemp == false)
                        {
                            //runLogInfo.RunLog = $"分配目标位写入报文失败";
                            //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                            _logUtil.Error($"请求目标位：托盘【{plcMessage.PalletBarcode}】重复请求目标位，PLC设备【{plcMessage.EquipmentCode}】请求目标位写入报文失败");
                            return;
                        }
                        else
                        {
                            runLogInfo.RunLog = $"请求目标位：托盘【{plcMessage.PalletBarcode}】重复请求请求目标位，PLC设备【{plcMessage.EquipmentCode}】请求目标位写入报文成功,报文：{JsonConvert.SerializeObject(writeBo)}";
                            await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                        }

                        try
                        {
                            //同步更新wms任务状态为执行中
                            var flag = await WCSMessageWithWMSApi.WCSUpdateWMStaskStateAndProcessTaskStateAsync(wcsWorkTaskInfo.WmsTaskCode, (int)EnumTaskState.Executing);
                            if (flag)
                            {
                                wcsWorkTaskInfo.UploadWmsState = EnumUploadWmsState.Succeed;
                                wcsWorkTaskInfo.UploadWmsTime = DateTime.Now;
                            }
                            else
                            {
                                wcsWorkTaskInfo.UploadWmsState = EnumUploadWmsState.Failed;
                                wcsWorkTaskInfo.UploadWmsTime = DateTime.Now;
                            }
                            _logUtil.Debug($"请求目标位：托盘【{plcMessage.PalletBarcode}】重复请求请求目标位，PLC设备【{plcMessage.EquipmentCode}】 任务号：{wcsWorkTaskInfo.WmsTaskCode}上报WMS状态 {flag}");
                            await _workTaskInfoRepository.UpdateAsync(wcsWorkTaskInfo);
                        }
                        catch (Exception ex)
                        {
                            //runLogInfo.RunLog = $"任务号{workTaskInfo.WmsTaskCode}:向Wms同步状态更新失败";

                            //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                            _logUtil.Error($"请求目标位：托盘【{plcMessage.PalletBarcode}】重复请求请求目标位，PLC设备【{plcMessage.EquipmentCode}】任务号{wcsWorkTaskInfo.WmsTaskCode}:向Wms同步状态更新失败，报错 ex={ex.Message}");
                        }
                        return;
                    }
                }

                //写入正常报文
                writeBo.TaskCode = 0;
                writeBo.PalletBarcode = wcsWorkTaskInfo.PalletCode;
                writeBo.ToEquipmentCode = 0;
                writeBo.ActionType = 99;
                writeBo.AlrmCode = 134;
                var writeBl = await plcConn.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize());
                _IRedisHelper.SetStringKey($"PLC-{plcMessage.EquipmentCode}", plcMessage.EquipmentCode.ToString() + plcMessage.AlrmCode, TimeSpan.FromSeconds(10));
                if (!writeBl)
                {
                    //runLogInfo.RunLog = $"请求分配重复:写入正常报文报文失败";
                    //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);

                    _logUtil.Error($"请求目标位：托盘【{plcMessage.PalletBarcode}】投料口申请任务重复，PLC设备【{plcMessage.EquipmentCode}】写入PLC失败！");
                    return;
                }
                else
                {
                    runLogInfo.RunLog = $"请求目标位：托盘【{plcMessage.PalletBarcode}】投料口申请任务重复，PLC设备【{plcMessage.EquipmentCode}】写入PLC成功！写入报文：{JsonConvert.SerializeObject(writeBo)}";
                    //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                    _logUtil.Error(runLogInfo.RunLog);

                }
                return;
            }
            #endregion

            #region wcs托盘上架任务NA逻辑处理
            WmsTaskInfoDto workTaskDto = null;
            try
            {
                //向wms读取巷道分配任务
                WMSApiDomain.WebApi.HeaderResult<WmsTaskInfoDto> res = await WCSMessageWithWMSApi.WCSCreatUploadWarehouseWMSTaskAsync(plcMessage.PalletBarcode, plcMessage.EquipmentCode);
                if (res.IsSucceed)
                {
                    workTaskDto = res.Result;
                }
                else
                {
                    var msg = res.Message;
                    //添加判断去恒益能的打包台
                    if (msg.Contains("分选后托盘去恒翼能打包台"))
                    {
                        //写入正常报文到Plc
                        writeBo.TaskCode = 1001;//wcs任务号
                        writeBo.ToEquipmentCode = 888888;//目标设备编号
                        //plc给什么握手回什么握手
                        writeBo.ActionType = plcMessage.ActionType;
                        var writehyn = await plcConn.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize());


                        if (writehyn == false)
                        {
                            //runLogInfo.RunLog = $"分配目标位写入报文失败";
                            //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                            _logUtil.Error($"请求目标位：托盘【{plcMessage.PalletBarcode}】请求目标位，去恒翼能打包台。PLC设备【{plcMessage.EquipmentCode}】请求目标位写入报文失败");
                            return;
                        }
                        else
                        {
                            runLogInfo.RunLog = $"请求目标位：托盘【{plcMessage.PalletBarcode}】请求目标位，去恒翼能打包台。PLC设备【{plcMessage.EquipmentCode}】请求目标位写入报文成功,报文：{JsonConvert.SerializeObject(writeBo)}";
                            await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                        }
                        return;
                    }
                    runLogInfo.RunLog = $"向Wms请求任务失败:{msg}";
                    //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);

                    if (msg.Contains("没有配置工位信息"))
                        writeBo.AlrmCode = 20;
                    if (msg.Contains("NG分选机出口扫码位置流程报错"))
                        writeBo.AlrmCode = 21;
                    if (msg.Contains("不存在业务类型数据"))
                        writeBo.AlrmCode = 22;
                    if (msg.Contains("扫码位置流程报错"))
                        writeBo.AlrmCode = 23;
                    if (msg.Contains("投入口无法查询对应的流程"))
                        writeBo.AlrmCode = 24;
                    if (msg.Contains("没有绑定流程参数"))
                        writeBo.AlrmCode = 25;
                    if (msg.Contains("节点数据配置异常"))
                        writeBo.AlrmCode = 26;
                    if (msg.Contains("未配置巷道分配关联数据"))
                        writeBo.AlrmCode = 27;
                    if (msg.Contains("未配置巷道分配关联明细数据"))
                        writeBo.AlrmCode = 28;
                    if (msg.Contains("未配置巷道分组指针"))
                        writeBo.AlrmCode = 29;
                    if (msg.Contains("没有可用巷道"))
                        writeBo.AlrmCode = 30;
                    if (msg.Contains("不存在流程配置参数数据"))
                        writeBo.AlrmCode = 43;
                    if (msg.Contains("未解绑"))
                        writeBo.AlrmCode = 41;
                    if (msg.Contains("不存在托盘数据"))
                        writeBo.AlrmCode = 44;
                    if (msg.Contains("流程节点应为待处理状态！请查看OCV数据是否上传"))
                        writeBo.AlrmCode = 47;
                    if (msg.Contains("请调整对应流程节点状态为待处理状态"))
                        writeBo.AlrmCode = 48;
                    if (msg.Contains("绑定的流程配置有误！，OCV没测试排出"))
                        writeBo.AlrmCode = 49;
                    if (msg.Contains("无法获取对应电池类型配置的流程参数"))
                        writeBo.AlrmCode = 50;
                    if (msg.Contains("任务到达上限"))
                        writeBo.AlrmCode = 51;
                    if (msg.Contains("没有上传数据"))
                        writeBo.AlrmCode = 52;
                    if (msg.Contains("同楼层巷道缓存已满"))
                        writeBo.AlrmCode = 54;
                    //不存在托盘数据
                    if (writeBo.AlrmCode ==0)
                        writeBo.AlrmCode = 3;

                    writeBo.ActionType = 99;
                    var writeBl = await plcConn.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize());

                    _logUtil.Error($"请求目标位1：请求目标位，PLC设备【{plcMessage.EquipmentCode}】申请任务报警！内容：{msg}");
                    _IRedisHelper.SetStringKey($"PLC-{plcMessage.EquipmentCode}", plcMessage.EquipmentCode.ToString() + plcMessage.AlrmCode, TimeSpan.FromSeconds(10));

                    return;
                }
            }
            catch (Exception ex)
            {
                //if (ex.Message.Contains("at") && ex.Message.Contains("System.Exception:"))
                //{

                //    var msg = ex.Message.Split("at").First().Split("System.Exception:");
                //    runLogInfo.RunLog = $"向Wms请求任务失败:{msg[1]}";

                //}
                //else
                //{
                //    var msg = ex.Message.Length > 150 ? ex.Message.Substring(0, 100) : ex.Message;
                //    runLogInfo.RunLog = $"向Wms请求任务失败:{msg}";
                //}
                //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                _logUtil.Error($"请求目标位：请求目标位，PLC设备【{plcMessage.EquipmentCode}】申请任务报错！内容：{ex.Message}");
            }

            //wms请求失败处理 写入100报警握手类型
            if (workTaskDto == null)
            {
                //runLogInfo.RunLog = $"向Wms请求任务失败WMS返回空";
                //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                _logUtil.Error($"请求目标位：托盘【{plcMessage.PalletBarcode}】请求目标位，PLC设备【{plcMessage.EquipmentCode}】向Wms请求任务失败WMS返回空");
                writeBo.ActionType = 99;
                writeBo.AlrmCode = 3;
                var writeBl = await plcConn.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize());
                //if (writeBl == false)
                //{
                //    runLogInfo.RunLog = $"向Wms请求任务失败：向PLC写入报文失败";
                //}
                //else
                //{
                //    runLogInfo.RunLog = $"向Wms请求任务失败：向PLC写入报文成功";
                //}
                //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                _IRedisHelper.SetStringKey($"PLC-{plcMessage.EquipmentCode}", plcMessage.EquipmentCode.ToString() + plcMessage.AlrmCode, TimeSpan.FromSeconds(10));
                return;
            }

            //WorkTaskInfo数据补全
            var workTaskInfo = new WorkTaskInfo();

            long id = _snowflake.GetId();//雪花ID
            workTaskInfo.ID = id;
            //wcs任务code从wmstaskcode日开始截取
            int.TryParse(workTaskDto.TaskCode.ToString().Substring(6), out var wcsTaskCode);
            workTaskInfo.TaskCode = wcsTaskCode;
            //wms赋值
            workTaskInfo.WmsTaskCode = workTaskDto.TaskCode;
            workTaskInfo.DependWmsTaskCode = workTaskDto.DependWMSTaskCode;
            workTaskInfo.TaskType = Enum.Parse<EnumTaskType>(workTaskDto.TaskType.ToString());

            workTaskInfo.WmsFromPosition = workTaskDto.StartPosition;
            workTaskInfo.WmsToPosition = workTaskDto.EndPosition;
            workTaskInfo.WmsFromStation = workTaskDto.FromStation;
            workTaskInfo.WmsToStation = workTaskDto.ToStation;
            workTaskInfo.TaskProcessState = EnumTaskProcessState.Initial;
            workTaskInfo.TaskState = EnumTaskState.Executing;
            workTaskInfo.Priority = workTaskDto.Priority;

            //托盘条码
            workTaskInfo.PalletCode = plcMessage.PalletBarcode.Trim();




            #region 任务子任务信息赋值by RouteDetailInfo
            //获取配置巷道信息
            var routeConfigExp = Expressionable.Create<RouteInfo>();
            routeConfigExp.AndIF(true, (a) => a.FromStation == workTaskInfo.WmsFromStation && a.ToStation == workTaskInfo.WmsToStation);
            var routeInfo = await _workTaskInfoRepository.AsSugarClient()
                .Queryable<RouteInfo>()
                .Where(routeConfigExp.ToExpression())
                .Select((a) => new RouteInfo()
                {
                    ID = a.ID,
                    FromStation = a.FromStation,
                    ToStation = a.ToStation,
                }).FirstAsync();
            if (routeInfo == null)
            {
                _logUtil.Error($"请求目标位1：托盘【{plcMessage.PalletBarcode}】请求目标位，PLC设备【{plcMessage.EquipmentCode}】起始工位{workTaskInfo.WmsFromStation}目标工位{workTaskInfo.WmsToStation}获取工位失败");
                writeBo.AlrmCode = 108;
                writeBo.ActionType = 99;
                var flag = await plcConn.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize());
                _IRedisHelper.SetStringKey($"PLC-{plcMessage.EquipmentCode}", plcMessage.EquipmentCode.ToString() + plcMessage.AlrmCode, TimeSpan.FromSeconds(10));
                return;
            }

            //巷道详情信息获取
            var routeDetailConfigExp = Expressionable.Create<RouteDetailInfo>();
            routeDetailConfigExp.AndIF(true, (a) => a.RouteID == routeInfo.ID && a.IsStart);
            var routeDetailInfo = await _workTaskInfoRepository.AsSugarClient()
                .Queryable<RouteDetailInfo>()
                .Where(routeDetailConfigExp.ToExpression())
                .Select((a) => new
                {
                    a.ID,
                    a.RouteID,
                    a.FromCargo,
                    a.ToCargo,
                    a.DispatchType,
                    a.FromEquipment,
                    a.ToEquipment,

                }).FirstAsync();

            if (routeDetailInfo == null)
            {
                //runLogInfo.RunLog = $"巷道路径详情配置信息起始工位{workTaskInfo.WmsFromStation}目标工位{workTaskInfo.WmsToStation}获取设备路径失败";
                //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                _logUtil.Error($"请求目标位：托盘【{plcMessage.PalletBarcode}】请求目标位，PLC设备【{plcMessage.EquipmentCode}】巷道路径详情配置信息起始工位{workTaskInfo.WmsFromStation}目标工位{workTaskInfo.WmsToStation}获取设备路径失败");
                writeBo.AlrmCode = 109;
                writeBo.ActionType = 99;
                var flag = await plcConn.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize());
                _IRedisHelper.SetStringKey($"PLC-{plcMessage.EquipmentCode}", plcMessage.EquipmentCode.ToString() + plcMessage.AlrmCode, TimeSpan.FromSeconds(10));
                return;
            }

            workTaskInfo.CurrentToEquipment = routeDetailInfo.ToEquipment;


            workTaskInfo.CurrentFromCargo = routeDetailInfo.FromCargo;
            workTaskInfo.CurrentToCargo = routeDetailInfo.ToCargo;
            workTaskInfo.RouteID = routeDetailInfo.RouteID;
            workTaskInfo.CurrentRounteDetailID = routeDetailInfo.ID;
            workTaskInfo.CurrentDispatchType = routeDetailInfo.DispatchType;
            //起始设备位 
            workTaskInfo.CurrentFromEquipment = workTaskInfo.WmsFromPosition; //WMS 作业实际起点设备
                                                                              // workTaskInfo.CurrentToEquipment = routeDetailInfo.ToEquipment;
            workTaskInfo.CurrentDetailTaskState = EnumDetailTaskState.Executing;
            workTaskInfo.CurrentCreateTime = DateTime.Now;
            workTaskInfo.CurrentUpdateTime = DateTime.Now;
            #endregion

            workTaskInfo.SaveTime = DateTime.Now;
            workTaskInfo.UpdateTime = DateTime.Now;

            #region 同步更新wms任务状态&写入正常报文
            //写入正常报文到Plc
            writeBo.TaskCode = workTaskInfo.TaskCode;//wcs任务号
            writeBo.ToEquipmentCode = workTaskInfo.CurrentToEquipment.ToInt32();//目标设备编号
            writeBo.ActionType = plcMessage.ActionType;

            //runLogInfo.RunLog = $"PLC写入报文内容： {JsonConvert.SerializeObject(writeBo)}";
            //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
            var writeResult = await plcConn.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize());

            if (writeResult == false)
            {
                //runLogInfo.RunLog = $"分配目标位写入报文失败";
                //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                _logUtil.Error($"请求目标位1：托盘【{plcMessage.PalletBarcode}】请求目标位，PLC设备【{plcMessage.EquipmentCode}】请求目标位写入报文失败");
                return;
            }
            else
            {
                runLogInfo.RunLog = $"请求目标位1：托盘【{plcMessage.PalletBarcode}】请求目标位，PLC设备【{plcMessage.EquipmentCode}】请求目标位写入报文成功,报文：{JsonConvert.SerializeObject(writeBo)}";
                await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
            }


            try
            {
                //同步更新wms任务状态为执行中
                var flag = await WCSMessageWithWMSApi.WCSUpdateWMStaskStateAndProcessTaskStateAsync(workTaskInfo.WmsTaskCode, (int)EnumTaskState.Executing);
                if (flag)
                {
                    workTaskInfo.UploadWmsState = EnumUploadWmsState.Succeed;
                    workTaskInfo.UploadWmsTime = DateTime.Now;
                }
                else
                {
                    workTaskInfo.UploadWmsState = EnumUploadWmsState.Failed;
                    workTaskInfo.UploadWmsTime = DateTime.Now;
                }
                _logUtil.Debug($"请求目标位：托盘【{plcMessage.PalletBarcode}】请求目标位，PLC设备【{plcMessage.EquipmentCode}】 任务号：{workTaskInfo.WmsTaskCode}上报WMS状态 {flag}");
                runLogInfo.RunLog = $"请求目标位：托盘【{plcMessage.PalletBarcode}】请求目标位，PLC设备【{plcMessage.EquipmentCode}】 任务号：{workTaskInfo.WmsTaskCode}上报WMS状态 {flag}";
                await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
            }
            catch (Exception ex)
            {
                //runLogInfo.RunLog = $"任务号{workTaskInfo.WmsTaskCode}:向Wms同步状态更新失败";

                //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                _logUtil.Error($"请求目标位：托盘【{plcMessage.PalletBarcode}】请求目标位，PLC设备【{plcMessage.EquipmentCode}】任务号{workTaskInfo.WmsTaskCode}:向Wms同步状态更新失败，报错 ex={ex.Message}");
            }

            //WorkTaskInfo数据插入
            var expCheck = Expressionable.Create<WorkTaskInfo>();
            expCheck.AndIF(true, (a) => a.PalletCode == plcMessage.PalletBarcode && (a.TaskState == EnumTaskState.Initial || a.TaskState == EnumTaskState.Executing));
            var wcsCheckWorkTaskInfo = await _workTaskInfoRepository.GetFirstAsync(expCheck.ToExpression());
            if (wcsCheckWorkTaskInfo == null)
            {
                bool bl = await _workTaskInfoRepository.InsertAsync(workTaskInfo);
            }

            //查询重复任务 
            var taskList = await _workTaskInfoRepository.AsSugarClient().Queryable<WorkTaskInfo>()
                .Where(t => t.PalletCode == workTaskInfo.PalletCode
                            && t.TaskState == workTaskInfo.TaskState
                            && t.RouteID == workTaskInfo.RouteID
                            && t.CurrentRounteDetailID == workTaskInfo.CurrentRounteDetailID)
                .ToListAsync();
            //两条相同任务以上就只保留一条
            if (taskList.Count > 1)
            {
                var tempTaskList = taskList.Remove(taskList[0]);
                if (tempTaskList)
                {
                    await _workTaskInfoRepository.AsSugarClient().Deleteable(taskList).ExecuteCommandAsync();
                    _logUtil.Debug($"请求目标位：托盘【{plcMessage.PalletBarcode}】请求目标位，PLC设备【{plcMessage.EquipmentCode}】删除重复任务数： {taskList.Count}, 任务号：{workTaskInfo.WmsTaskCode}");
                }
            }
            #endregion

            #endregion

        }

        /// <summary>
        /// 根据写入db配置将报文写入plc
        /// </summary>
        /// <param name="equipmentCode">设备编号</param>
        /// <param name="plcConnectionId"></param>
        /// <param name="bytes"></param>
        /// <returns></returns>
        private async Task<bool> WriteDbAsync(string equipmentCode, long plcConnectionId, byte[] bytes)
        {
            var plcConn = _plcConnectionPool.S7GetWritePlcConnection(plcConnectionId);
            //根据设备编号获取写入配置
            var writeConfig = await _plcWriteDbInfoRepository.GetSingleAsync(s => s.EquipmentCode == equipmentCode
            && s.PlcConnectionId == plcConnectionId && s.ObjectType == typeof(PlanarGeneralWriteWcsAction).Name);
            //写入报文处理
            bool isSend = await plcConn.WriteDbAsync(writeConfig.DbCode, writeConfig.DbStart, bytes);
            if (isSend)
                _logUtil.Info($"设备号{equipmentCode}plc连接ID{plcConnectionId} 写入报文成功");
            else
                _logUtil.Info($"设备号{equipmentCode}plc连接ID{plcConnectionId} 写入报文失败");
            return isSend;
        }

    }
}
